namespace FIREFLYX {
    /**
     * cube纹理 的面
     */
    export enum TextureCubeFace {
        /** X 正面 */
        POSITIVE_X = WebGL2RenderingContext.TEXTURE_CUBE_MAP_POSITIVE_X,
        /** X 反面 */
        NEGATIVE_X = WebGL2RenderingContext.TEXTURE_CUBE_MAP_NEGATIVE_X,
        /** Y 正面 */
        POSITIVE_Y = WebGL2RenderingContext.TEXTURE_CUBE_MAP_POSITIVE_Y,
        /** Y 反面 */
        NEGATIVE_Y = WebGL2RenderingContext.TEXTURE_CUBE_MAP_NEGATIVE_Y,
        /** Z 正面 */
        POSITIVE_Z = WebGL2RenderingContext.TEXTURE_CUBE_MAP_POSITIVE_Z,
        /** Z 反面 */
        NEGATIVE_Z = WebGL2RenderingContext.TEXTURE_CUBE_MAP_NEGATIVE_Z,
    }

    /**
     * cube 纹理
     */
    export class TextureCube extends TextureBase {
        constructor(name: string = "", uuid?: string) {
            super(name, uuid);
            const gl = App.webgl2;
            // this.texelType = gl.UNSIGNED_BYTE;
            let glTex = gl.createTexture();
            if (glTex != null) this._glTextrue = glTex;
            this._paramSetting = new TextureParamSetting();
        }

        private _paramSetting: TextureParamSetting;
        private static readonly _faceList = [
            TextureCubeFace.POSITIVE_X,
            TextureCubeFace.NEGATIVE_X,
            TextureCubeFace.POSITIVE_Y,
            TextureCubeFace.NEGATIVE_Y,
            TextureCubeFace.POSITIVE_Z,
            TextureCubeFace.NEGATIVE_Z,
        ];

        private _sizeMap: { [face: number]: number[] } = {
            [TextureCubeFace.POSITIVE_X]: [1, 1],
            [TextureCubeFace.NEGATIVE_X]: [1, 1],
            [TextureCubeFace.POSITIVE_Y]: [1, 1],
            [TextureCubeFace.NEGATIVE_Y]: [1, 1],
            [TextureCubeFace.POSITIVE_Z]: [1, 1],
            [TextureCubeFace.NEGATIVE_Z]: [1, 1],
        };

        /** 参数设置 */
        public get paramSetting() { return this._paramSetting; }

        public apply() {
            const gl = App.webgl2;
            TextureParamSetting.applyTex(gl.TEXTURE_CUBE_MAP, this._glTextrue, this._paramSetting);
        }

        /**
         * 获取 指定面 纹理的宽度
         * @param face cube指定面
         * @returns 纹理的宽度
         */
        public getWidth(face: TextureCubeFace) {
            return this._sizeMap[face][0];
        }

        /**
         * 获取 指定面 纹理的高度
         * @param face cube指定面
         * @returns 纹理的高度
         */
        public getHeight(face: TextureCubeFace) {
            return this._sizeMap[face][1];
        }

        /**
         * 设置纹理数据(纹理图像资源)
         * @param imgData 纹理图像资源
         */
        public setTextureData(imgData: TexImageSource, face: TextureCubeFace): void;
        /**
         * 设置纹理数据
         * @param imgData 纹理二进制缓存
         * @param width 纹理宽度
         * @param height 纹理高度
         */
        public setTextureData(imgData: Uint8Array, face: TextureCubeFace, width: number, height: number): void;
        public setTextureData(imgData: TexImageSource | Uint8Array, face: TextureCubeFace, width?: number, height?: number): void {
            if (!imgData) return;
            const gl = App.webgl2;
            const param = this._paramSetting;
            // let oldUPA = gl.getParameter(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL) as boolean;
            // let oldUFY = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL) as boolean;
            //绑定指定纹理对象
            gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glTextrue);
            // //像素存储参数设置
            // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, param.premultiplyAlpha);
            // gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, param.flipY);

            let glFormat = param.getGLFormat();
            const size = this._sizeMap[face];
            //上传纹理数据
            if (width == null || height == null) {
                let image = (imgData as TexImageSource);
                gl.texImage2D(face, 0, param.format, glFormat, param.texelType, image);
                size[0] = (image as any).width ?? 1;
                size[1] = (image as any).height ?? 1;
            } else {
                gl.texImage2D(face, 0, param.format, width, height, 0, glFormat, param.texelType, (imgData as Uint8Array));
                size[0] = width;
                size[1] = height;
            }

            // //还原存储参数设置
            // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, oldUPA);
            // gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, oldUFY);
            //解除绑定
            gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
        }

        /**
         * 设置Cube的所有面的纹理数据(纹理图像资源)
         * @param imgDatas 纹理图像资源列表 
         * 顺序为 ：X 正面 、X 反面 、Y 正面 、Y 反面 、Z 正面 、Z 反面
         */
        public setTextureAllData(imgDatas: TexImageSource[]): void
        /**
         * 设置Cube的所有面的纹理数据
         * @param imgDatas 纹理图像资源列表
         * @param width 纹理宽
         * @param height 纹理高
         */
        public setTextureAllData(imgDatas: Uint8Array[], width: number, height: number): void
        public setTextureAllData(imgDatas: (TexImageSource | Uint8Array)[], width?: number, height?: number): void {
            if (!imgDatas) {
                console.error(`imgData is null`);
                return;
            }
            const imgsLen = imgDatas.length;
            const len = imgsLen < 0 ? 0 : imgsLen > 6 ? 6 : imgsLen;
            for (let i = 0; i < len; i++) {
                const face = TextureCube._faceList[i];
                const imgData = imgDatas[i];
                if (width == null || height == null) {
                    this.setTextureData(imgData as TexImageSource, face);
                } else {
                    this.setTextureData(imgData as Uint8Array, face, width, height);
                }
            }
        }

        public dispose(): void {
            super.dispose();

            const len = TextureCube._faceList.length;
            for (let i = 0; i < len; i++) {
                const k = TextureCube._faceList[i];
                delete this._sizeMap[k];
            }
            (this._sizeMap as any) = null;
            (this._paramSetting as any) = null;
        }
    }
}